import Util from "@/js/Util"
import * as math_ from 'mathjs'
import Decimal from 'decimal.js';
import dayjs from 'dayjs'
import I18Parse from '@/common/i18Parse'
import { Function } from "eval5";

let Formula={};
/**
 * 设置缓存。
 */
Formula.IF_ELSE = function (express, res1, res2) {
    let result = express;
    if (typeof express === "string") {
        if(!express.includes('return')){
            express = `return ${express};`;
        }
        let func = new Function(express)
        result = func();
    }
    return result?res1:res2;
}

/**
 * 子表求和
 * @param {self} 表单this
 * @param {tableField} 子表字段
 * @param {calc} 行计算
 * @param {fixed} 精度
 */
function calcSubTable(self, tableField, calc, fixed, than) {
    let tmp = 0;
    let tableData = self.data[`sub__${tableField}`] || [];
    if (tableData.length === 0 || !calc) {
        return 0
    }
    for (let [index,item] of tableData.entries()) {
        if (!calc.includes('return ')) {
            calc = `return ${calc}`
        }
        let x = new Function('Formula', 'row', 'data','rowIndex', calc).call(self, than, item, self.data,index);
        tmp = than.Add(tmp, x);
    }
    if (fixed && !isNaN(fixed)) {
        tmp = new Decimal(tmp);
        tmp = tmp.toFixed(fixed);
    }
    return tmp;
}

/**
 * 子表求和
 * @param {self} 表单this
 * @param {tableField} 子表字段
 * @param {calc} 行计算
 * @param {fixed} 精度
 */
Formula.SUB_SUM = function (self, tableField, calc, fixed) {
    let tmp = calcSubTable(self, tableField, calc, fixed, this)
    return parseFloat(tmp)
};
Formula.SubSum = function (self, tableField, calc, fixed) {
    return Formula.SUB_SUM(self, tableField, calc, fixed)
}
/**
 * 子表求平均数
 * @param {self} 表单this
 * @param {tableField} 子表字段
 * @param {calc} 行计算
 * @param {fixed} 精度
 */
Formula.SUB_AVERAGE = function (self, tableField, calc, fixed) {
    let tableData = self.data[`sub__${tableField}`] || [];
    if (tableData.length === 0) {
        return 0
    }
    let tmp = calcSubTable(self, tableField, calc, fixed, this)
    let size = tableData.length;
    return parseFloat(tmp / size)
};



/**
 * 子表求最数
 * @param {Object} ary
 */
Formula.SUB_EXTREME = function (self, tableField,colField, extreme) {
    let tableData = self.data[`sub__${tableField}`] || [];
    if (tableData.length === 0) {
        return 0
    }
    let arr = tableData.map(item=>typeof item[colField] === 'string'?Number(item[colField]):item[colField]);
    //最大值
    if ("max" === extreme) {
        return Math.max(...arr);
    }
    //最小值
    else if ("min" === extreme) {
        return Math.min(...arr);
    }
    return '';
};


/**
 * 获取数据为空则为0
 * @param {Object} num
 */
Formula.NUM = function(num) {
    if(!num) return 0;
    if(isNaN(num)) return 0;
    return parseFloat(num);
}

Formula.CONCAT = function(char1,char2) {
    if(!char2){
        return char1;
    }
    return char1+char2;
}

/**
 * 比较两个日期的差值
 * @param date1     日期1
 * @param date2     日期2
 * @param unit      单位 （years,months,weeks,days,hours,minutes,seconds)
 * @param fixed     小数位数
 * @param amend     修正值
 * @returns {string|number}
 * @constructor
 */
Formula.DateDif = function (date1, date2, unit, fixed, amend, format) {
    return Formula.DATEDIF(date1, date2, unit, fixed, amend, format)
}
Formula.DATEDIF = function (date1, date2, unit, fixed, amend, format) {
    if (!date1 || !date2) return "";
    if (!format) {
        format = "YYYY-MM-DD HH:mm:ss";
    }
    //unit当时大写要改成小写
    //常见 unit 参数：
    // 'y'：年份
    //'M'：月份
    //'d'：天数
    //'h'：小时
    // 'm'：分钟
    //'s'：秒
    if(unit && unit=='Y'){
        unit=unit.toLowerCase();
    }
    let val = dayjs(date1, format).diff(dayjs(date2, format), unit, true);
    if (!isNaN(fixed)) {
        val = Number(val.toFixed(fixed));
    }
    if (amend) {
        val += amend;
    }
    return val;
}
/**
 * 对JSON字符串进行解析，并返回 value值。
 * @param str
 * @returns {*}
 * @constructor
 */
Formula.GETVALUE = function(str){
    if( !str ){ return ""};
    return JSON.parse(str).value;
}


/*
 * 日期计算 例如日期+天数=日期
 *
 * CALC_DATE({开始时间},{时间数},[单位],[方式]),
 * 单位可以是'Y(years)'、Q(quarters)'、'M(months)'、
	'w(weeks)'、'd(days)、'h(hours)'、
	'm(minutes)'、's(seconds)',
	方式可以是 ‘+’、‘-’
	日期格式: ‘YYYY-MM-DD HH:mm:ss’
 */
Formula.CALC_DATE=function(date,time,unit,mode,formatStr){
    if(!date) return "";
    if(!time){
        return date;
    }
    let val;
    if(!formatStr){
        formatStr='YYYY-MM-DD HH:mm:ss';
    }
    if(mode=='-'){
        val=dayjs(date).subtract(time, unit);
    }else {
        val=dayjs(date).add(time, unit);
    }
    if(formatStr){
        val=val.format(formatStr)
    }
    return val;
}

//IOS 日期为2020/02/05
Formula.getTime=function(obj){
    if(obj instanceof Date) {
        return obj.getTime();
    } else if(obj) {
        let dateObj = new Date(obj);
        //没有转换到
        if(isNaN(dateObj.getTime()) || !dateObj instanceof Date) {
            dateObj = new Date(obj.replace(/-/g, '/'));
        }
        return dateObj.getTime();
    }
}


/**
 * 四舍五入函数
 * @param {Object} numberRound		需要四舍五入的函数
 * @param {Object} roundDigit		位数
 */
Formula.ROUND=function(numberRound,roundDigit){
    if   (numberRound>=0){
        let   tempNumber   =   parseInt((numberRound   *   Math.pow(10,roundDigit)+0.5))/Math.pow(10,roundDigit);
        return   tempNumber;
    } else{
        let   tempNumber   =   parseInt((-numberRound   *   Math.pow(10,roundDigit)+0.5))/Math.pow(10,roundDigit);
        return   -tempNumber;
    }
}

/**
 * 中文大写
 * @param value
 * @constructor
 */
Formula.UPPERCASE=function(value){
    return Util.toChineseMoney(value);
}

/**
 * 格式化数值
 * @param value
 * @param format 默认逗号
 * @constructor
 */
Formula.FORMAT_VALUE=function(value,format){
    return Util.formatNumber(value,format);
}


Formula.mathCalc = (data, type) => {
    data = data.map(item => typeof item === 'string' ? Number(item) : item)
    //type -> add(加) subtract(减) multiply(乘) divide(除)
    if (data && data.length > 0) {
        let val = Number(data[0]);
        if (!val && val != 0) {
            return 0;
        }
        if (val === 0 && ['multiply', 'divide'].includes(type)) {
            return 0;
        }
        for (let i = 1; i < data.length; i++) {
            let lastNumber = Number(math_.format(math_.bignumber(data[i])));
            if (lastNumber === 0 && ['divide','multiply'].includes(type)) {
                //省心操作，在乘或者除的时候遇到 0 直接返回0; 忽略了除数不能为0的特点;
                return 0;
            }
            val = Number(math_.format(math_[type](math_.bignumber(val), math_.bignumber(data[i]))))
        }
        return val;
    }
    return 0;
}
/*相加*/
Formula.Add = function (...data) {
    return Formula.mathCalc(data,'add');
}

/*相减*/
Formula.Subtract = (...data)=>{
    return Formula.mathCalc(data,'subtract');
}

/*相乘*/
Formula.Multiply = function (...data) {
    return Formula.mathCalc(data, 'multiply');
}
/*相除*/
Formula.Divide =function (...data){
    return Formula.mathCalc(data,'divide');
}

/**
 * 四舍五入函数
 */
Formula.HALF_ADJUST = function(val,fixed) {
    if(!val){ return val}
    if(!isNaN(fixed)){
        val = new Decimal(val);
        val=val.toFixed(fixed);
    }
    return parseFloat(val);
}

/**
 * 判断数据是否为空，{“label”:"",value:""}也算空
 */
Formula.ISNOTEMPTY = function (val) {
    let isJson =Util.isJson(val);
    if(isJson){
        let obj=val
        if (typeof  val == 'string'){
            try {
                obj=JSON.parse(val);
            }catch (e){
                obj=JSON.parse(val.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": '));
            }
        }
        if (Array.isArray(obj)){
            return obj.length != 0;
        }else{
            // 对象的值其中一个不为空即可
            for(let key in obj){
                if (obj[key] != null && obj[key].trim().length>0) {
                    return true;
                }
            }
            // 所有key都为‘’或者不存在时，返回false
            return false
        }
    }else {
        return val!=null && val!="";
    }
}

Formula.DATEDIF_ONEFIELD = function (date, unit, fixed, amend) {
    if (!date) return "";
    let aryDate = date.split(",");
    let val = dayjs(aryDate[1]).diff(dayjs(aryDate[0]), unit, true);
    if (!isNaN(fixed)) {
        val = Number(val.toFixed(fixed));
    }
    if (amend) {
        val += amend;
    }
    return val;
}
Formula.DateDifOneField = function (date, unit, fixed, amend) {
    return Formula.DATEDIF_ONEFIELD(date, unit, fixed, amend)
}

Formula.CalcDate = function (date, time, unit, mode, formatStr) {
    return Formula.CALC_DATE(date, time, unit, mode, formatStr)
}

/**
 * 数字截取小数位.
 * @param {number} numberValue       需要处理的数字
 * @param {number} roundDigit        小数位数
 * @param {boolean} isRound          是否四舍五入
 * @returns {number}                 处理后的数字
 */
Formula.FormatDecimal = function (numberValue, roundDigit, isRound) {
    //默认保留0位
    if (typeof roundDigit !== 'number' || roundDigit < 0 || !Number.isInteger(roundDigit)) {
        roundDigit = 0;
    }
    //默认四舍五入
    if (typeof isRound !== 'boolean') {
        isRound = true;
    }
    const factor = Math.pow(10, roundDigit);
    if (isRound) {
        return Math.round(numberValue * factor) / factor;
    } else {
        return Math.floor(numberValue * factor) / factor;
    }
};


Date.prototype.Format = function(fmt){ //author: meizz
    let o = {
        "M+" : this.getMonth()+1,                 //月份
        "d+" : this.getDate(),                    //日
        "h+" : this.getHours(),                   //小时
        "m+" : this.getMinutes(),                 //分
        "s+" : this.getSeconds(),                 //秒
        "q+" : Math.floor((this.getMonth()+3)/3), //季度
        "S"  : this.getMilliseconds()             //毫秒
    };
    if(/(y+)/.test(fmt))
        fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
    for(let k in o)
        if(new RegExp("("+ k +")").test(fmt))
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
    return fmt;
}

/**
 * 日期相减。
 * 参数1： date
 * 参数2：减的日期格式。
 * @param {Object} date
 * @param {Object} format
 */
Date.prototype.subtract = function(date,format,fixed){
    let minute= (this.getTime() - date.getTime())/(60 * 1000);
    let day=parseFloat(minute / (24*60));
    let hour=parseFloat(minute / 60);
    let rtn=0;
    switch(format){
        //分钟
        case 1:
            rtn=minute  ;
            break;
        //小时
        case 2:
            rtn=hour ;
            break;
        //天数
        default :
            rtn=day;
    }
    if(fixed){
        rtn=rtn.toFixed(fixed);
    }
    return rtn;
}

String.prototype.replaceAll=function(toReplace,replaceWith){
    let reg=new RegExp(toReplace,"igm");
    let rtn= this.replace(reg,replaceWith);
    return rtn;
}

String.prototype.startWith=function(str){
    let reg=new RegExp("^"+str);
    return reg.test(this);
}

String.prototype.endWith=function(str){
    let reg=new RegExp(str+"$");
    return reg.test(this);
}

String.prototype.trim=function(){
    return this.replace(/(^\s*)|(\s*$)/g, "");
}

/**
 * 将字符串解析为日期。
 */
String.prototype.parseDate=function(){
    //yyyy-MM-dd
    let aryDateTime=this.split(" ");
    let date=aryDateTime[0];
    let aryTmp=date.split("-");
    let year=parseInt(aryTmp[0]);
    let mon=parseInt(aryTmp[1])-1;
    let day=parseInt(aryTmp[2]);
    let hour=0;
    let minute=0;
    if(aryDateTime.length==2){
        let time=aryDateTime[1];
        let aryTmp=time.split(":");
        hour=parseInt(aryTmp[0]);
        minute=parseInt(aryTmp[1]);
    }
    return new Date(year,mon,day,hour,minute);
}

Array.prototype.contains = function (obj) {
    for(let i=0;i<this.length;i++){
        if(this[i]==obj){
            return true;
        }
    }
    return false;
}

let lang = uni.getStorageSync('language') || 'zh-CN';

/**
 * 自定义验证规则。
 */
let VTypes={
    isEnglish:{
        msg:I18Parse.getI18Val(lang,'engorUnder', '必须输入英文或下划线'),
        valid:function(v){
            if (/^[a-zA-Z\_]+$/g.test(v)) return true;
            return false;
        }
    },
    isEnglishAndNumber:{
        msg:I18Parse.getI18Val(lang,'engorNum', '必须输入英文或数字'),
        valid:function(v){
            if (/^[0-9a-zA-Z\_]+$/g.test(v)) return true;
            return false;
        }
    },
    isKeyLabel:{
        msg:I18Parse.getI18Val(lang,'startEng', '必须输入英文开头'),
        valid:function(v){
            if (/^[a-zA-Z][a-zA-Z0-9]*$/.test(v)) return true;
            return false;
        }
    },
    isNumber:{
        msg:I18Parse.getI18Val(lang,'mustInputNum', '必须输入数字'),
        valid:function(v){
            if (/^[-+]?[0-9]+(\.[0-9]+)?$/g.test(v)) return true;
            return false;
        }
    },
    isInteger:{
        msg:I18Parse.getI18Val(lang,'mustInteger', '必须输入整数'),
        valid:function(v){
            let re = new RegExp("^[-+]?[0-9]+$");
            if (re.test(v)) return true;
            return false;
        }
    },
    isPositiveInteger:{
        msg:I18Parse.getI18Val(lang,'mustPositiveInt', '必须输入正整数'),
        valid:function(v){
            if (/^[1-9]\d*$/g.test(v)) return true;
            return false;
        }
    },
    isNegtiveInteger:{
        msg:I18Parse.getI18Val(lang,'mustNegativeInt', '必须输入英文或数字'),
        valid:function(v){
            if (/^-[0-9]\d*$/g.test(v)) return true;
            return false;
        }
    },
    isFloat:{
        msg:I18Parse.getI18Val(lang,'floatingNum', '必须输入浮点数'),
        valid:function(v){
            if (/^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$/g.test(v)) return true;
            return false;
        }
    },
    isPositiveFloat:{
        msg:I18Parse.getI18Val(lang,'positiveFloadNum', '必须输入正浮点数'),
        valid:function(v){
            if (/^([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$/g.test(v)) return true;
            return false;
        }
    },
    isNegtiveFloat:{
        msg:I18Parse.getI18Val(lang,'negativeFloadNum', '必须输入负浮点数'),
        valid:function(v){
            if (/^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$/g.test(v)) return true;
            return false;
        }
    },
    isChinese:{
        msg:I18Parse.getI18Val(lang,'entered', '必须输入中文'),
        valid:function(v){
            let re = new RegExp("^[\u4e00-\u9fa5]+$");
            if (re.test(v)) return true;
            return false;
        }
    },
    IDCard:{
        msg:I18Parse.getI18Val(lang,'must1518Digits', '必须输入15-18位数字'),
        valid:function(v){
            if (/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(v)) return true;
            return false;
        }
    },
    isUrl:{
        msg:I18Parse.getI18Val(lang,'validUrl', '必须输入合法Url地址'),
        valid:function(v){
            let reg=new RegExp("^[A-Za-z]+://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$");
            if (reg.test(v)) return true;
            return false;
        }
    },
    isEmail:{
        msg:I18Parse.getI18Val(lang,'validEmail', '必须输入合法Email地址'),
        valid:function(v){
            if (/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/g.test(v)) return true;
            return false;
        }
    },
    isChinesePostCode:{
        msg:I18Parse.getI18Val(lang,'validPostalCode', '必须输入合法中国邮编地址'),
        valid:function(v){
            if (/^[1-9]\d{5}(?!\d)$/g.test(v)) return true;
            return false;
        }
    },
    isChinesePhone:{
        msg:I18Parse.getI18Val(lang,'lineNum', '必须输入合法中国固话号码'),
        valid:function(v){
            if (/^\d{3}-\d{8}|\d{4}-\d{7}$/g.test(v)) return true;
            return false;
        }
    },
    isChineseMobile:{
        msg:I18Parse.getI18Val(lang,'mobileNum', '必须输入合法中国手机号码'),
        valid:function(v){
            let re=new RegExp("^((13[0-9])|(15[^4,\\D])|(18[0,2,3,5-9]))\\d{8}$");
            if (re.test(v)) return true;
            return false;
        }
    },
    isIP:{
        msg:I18Parse.getI18Val(lang,'validIp', '必须输入合法IP地址'),
        valid:function(v){
            if (/^\d+\.\d+\.\d+\.\d+$/g.test(v)) return true;
            return false;
        }
    },
    isQQ:{
        msg:I18Parse.getI18Val(lang,'mustQq', '必须输入正确QQ号码'),
        valid:function(v){
            if (/^[1-9][0-9]{4,}$/g.test(v)) return true;
            return false;
        }
    },
    float:{
        msg:I18Parse.getI18Val(lang,'floatingNum', '必须输入浮点数'),
        valid:function(v){
            if (/^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0|\d*)$/g.test(v)) return true;
            return false;
        }
    },
    len:{
        msg:function(v,args){
            return I18Parse.getI18Val(lang,'onlyInputLength', '只允许输入长度为')+args;
        },
        valid:function(v,args){
            if(!v) return true;
            if(v.toString().length<=parseInt(args)){
                return true;
            }
            return false;
        }
    },
    length:{
        msg:function(v,args){
            return I18Parse.getI18Val(lang,'onlyInputLength', '只允许输入长度为')+args;
        },
        valid:function(v,args){
            if(!v) return true;
            if(v.toString().length<=parseInt(args)){
                return true;
            }
            return false;
        }
    },
    minnum:{
        msg:I18Parse.getI18Val(lang,'lessMinimun', '小于最小边界'),
        valid:function(v,args){
            if(v<parseFloat( args)){
                return false;
            }
            return true;
        }
    },
    maxnum:{
        msg:I18Parse.getI18Val(lang,'greaterMinimun', '大于最小边界'),
        valid:function(v,args){
            if(v>parseFloat(args)){
                return false;
            }
            return true;
        }
    }


}


/**
 * 根据vtype 进行验证。
 */
function _validVtype (val,vtype){
    let aryRule=vtype.split(";");
    for(let i=0;i<aryRule.length;i++){
        let rule=aryRule[i];
        let aryTmp=rule.split(":");
        let pre=aryTmp[0];
        let params="";
        let validObj=VTypes[pre];
        if(!validObj) continue;
        if(aryTmp.length==1){
            let rtn=validObj.valid(val);
            if(!rtn) {
                return {valid:false,msg:validObj.msg};
            }
        }
        else  if(aryTmp.length==2){
            params=aryTmp[1];
            let rtn=validObj.valid(val,params);
            if(!rtn) {
                return {valid:false,msg:(typeof validObj.msg== 'function')?validObj.msg(val,params):validObj.msg};
            }
        }
    }
    return {valid:true,msg:validObj.msg};
}


export {
    Formula,
    _validVtype,
    VTypes
}
